package MT::Test::Tags;

use strict;

if (MT->version_number < 4) {
    require MT::Template::Context;
    MT::Template::Context->add_container_tag(
                                           TestIs => \&MT::Test::Tags::test_is);
    MT::Template::Context->add_container_tag(
                                        TestIsNot => \&MT::Test::Tags::test_is);
    MT::Template::Context->add_container_tag(
                               TestCompareOK => \&MT::Test::Tags::test_compare);
    MT::Template::Context->add_container_tag(
                              TestListItem => \&MT::Test::Tags::test_list_item);
    MT::Template::Context->add_container_tag(
                                       TestLike => \&MT::Test::Tags::test_like);
    MT::Template::Context->add_container_tag(
                                     TestUnlike => \&MT::Test::Tags::test_like);
}

sub test_is {
    my ($ctx, $args, $cond) = @_;
    my $val = _get_test_value($ctx, $args);
    return unless defined $val;
    require MT::Test;
    my $tb        = MT::Test->builder;
    my $tag       = $ctx->stash('tag');
    my $test_name = $args->{test_name} || "MT$tag $val";
    my $builder   = $ctx->stash('builder');
    my $tokens    = $ctx->stash('tokens');
    my $out       = $builder->build($ctx, $tokens, $cond);
    return $ctx->error($builder->errstr) unless defined $out;
    lc $ctx->stash('tag') eq 'testisnot'
      ? $tb->isnt_eq($out, $val, $test_name)
      : $tb->is_eq($out, $val, $test_name);
    '';
}

sub test_compare {
    my ($ctx, $args, $cond) = @_;
    my $val = _get_test_value($ctx, $args);
    return unless defined $val;
    my $tag = $ctx->stash('tag');
    my $op  = $args->{op};
    return $ctx->error("MT$tag requires an 'op' argument.") unless ($op);
    require MT::Test;
    my $tb        = MT::Test->builder;
    my $test_name = $args->{test_name} || "MT$tag $val";
    my $builder   = $ctx->stash('builder');
    my $tokens    = $ctx->stash('tokens');
    my $out       = $builder->build($ctx, $tokens, $cond);
    return $ctx->error($builder->errstr) unless defined $out;
    $tb->cmp_ok($out, $op, $val, $test_name);
    '';
}

sub test_like {
    my ($ctx, $args, $cond) = @_;
    my $pattern = $args->{pattern};
    my $tag     = $ctx->stash('tag');
    return $ctx->error("MT$tag requires a 'pattern' argument.")
      unless ($pattern);
    require MT::Test;
    my $tb        = MT::Test->builder;
    my $test_name = $args->{test_name} || "MT$tag $pattern";
    my $builder   = $ctx->stash('builder');
    my $tokens    = $ctx->stash('tokens');
    my $out       = $builder->build($ctx, $tokens, $cond);
    return $ctx->error($builder->errstr) unless defined $out;
    lc $tag eq 'testunlike'
      ? $tb->unlike($out, qr/$pattern/, $test_name)
      : $tb->like($out, qr/$pattern/, $test_name);
    '';
}

sub test_list_item {
    my ($ctx, $args, $cond) = @_;
    my $tag   = $ctx->stash('tag');
    my $stash = $args->{stash};
    return $ctx->error("MT$tag requires an 'stash' argument.") unless ($stash);
    my $vals = $ctx->stash($stash);
    return $ctx->error(
                     "A $stash stash as an ARRAY reference was not in context.")
      unless ($vals && ref $vals eq 'ARRAY');
    require MT::Test;
    my $tb  = MT::Test->builder;
    my $val = shift @$vals;
    return $ctx->error("Out of values in '$stash' stash.") unless defined $val;
    my $test_name = $args->{test_name} || "MT$tag $val";
    my $builder   = $ctx->stash('builder');
    my $tokens    = $ctx->stash('tokens');
    my $out       = $builder->build($ctx, $tokens, $cond);
    return $ctx->error($builder->errstr) unless defined $out;
    $tb->is_eq($out, $val, $test_name);
    '';
}

sub _get_test_value {
    my ($ctx, $args) = @_;
    if ($args->{blank}) {
        return '';
    } elsif (defined $args->{value}) {
        return $args->{value};
    } elsif (defined $args->{stash}) {
        return $ctx->stash($args->{stash});
    } elsif (defined $args->{var}) {
        return MT->version_number() < 4
          ? $ctx->{__stash}{vars}{$args->{var}}
          : $ctx->var($args->{var});
    }
    my $tag = $ctx->stash('tag');
    $ctx->error("MT$tag did not define a value to compare.");
}

1;
